package controllers

import java.io.File

import dao._
import javax.inject.Inject
import org.joda.time.DateTime
import play.api.libs.json.Json
import play.api.mvc.{AbstractController, ControllerComponents}
import implicits.Implicits._
import models.Tables._
import shared.VarTool
import tool.Tool
import utils.Utils

import scala.concurrent.ExecutionContext.Implicits.global
import scala.io.Source

/**
 * Created by Administrator on 2019/8/14
 */
class DataInsertController @Inject()(cc: ControllerComponents, junctionDao: JunctionDao,
                                     fusionSymbolsDao: FusionSymbolsDao, modalSymbolsDao: ModalSymbolsDao,
                                     gtexIndexDao: GtexIndexDao,
                                     queryJunctionDao: QueryJunctionDao, queryFsJunctionDao: QueryFsJunctionDao,
                                     queryLsJunctionDao: QueryLsJunctionDao, detailBsDao: DetailBsDao,
                                     detailFsDao: DetailFsDao, detailLsDao: DetailLsDao,
                                     pancancerIndexDao: PancancerIndexDao,
                                     implicit val junctionLocationDao: JunctionLocationDao,
                                     implicit val gtexSupplementIndexDao: GtexSupplementIndexDao
                                    ) extends AbstractController(cc) {

  def insertBsJunctionF = {
    val kind = "BS"
    val parent = new File("C:\\rJunBase_database\\test")
    val file = new File(parent, "browse_BS_annotation.csv")
    val lines = file.csvLines.drop(1)
    val rows = lines.map { columns =>
      val location = columns(1)
      JunctionRow(columns(0), columns(1), columns(2), columns(3), columns(4), columns(5), columns(6), columns(7),
        columns(8), columns(9), columns(10), columns(11), columns(12), columns(13), columns(14), columns(15), "BS")
    }
    junctionDao.deleteAll(kind).flatMap { x =>
      junctionDao.insertAll(rows)
    }
  }

  def insertBsJunction = Action.async { implicit request =>
    insertBsJunctionF.map { x =>
      Ok("success!")
    }
  }

  def insertBs = Action.async { implicit request =>
    insertBsJunctionF.zip(insertBsJunctionLocationF).map { x =>
      Ok("success!")
    }
  }

  def insertBsJunctionLocationF = {
    val kind = "BS"
    val parent = new File("C:\\rJunBase_database\\test")
    val file = new File(parent, "browse_BS_annotation.csv")
    val lines = file.csvLines.drop(1)
    val rows = lines.map { columns =>
      val location = columns(1)
      val r = "^(chr[a-zA-Z0-9]+):(\\d+)\\|(\\d+):[^\\|]{1}$".r
      val r(chr1, chr1Pos, chr2Pos) = location
      JunctionLocationRow(columns(0), chr1, chr1Pos.toInt, chr1, chr2Pos.toInt, kind)
    }
    junctionLocationDao.deleteAll(kind).flatMap { x =>
      junctionLocationDao.insertAll(rows)
    }
  }

  def insertBsJunctionLocation = Action.async { implicit request =>
    insertBsJunctionLocationF.map { x =>
      Ok("success!")
    }
  }

  def insertQueryBsJunctionF = {
    val kind = "BS"
    val parent = new File("C:\\rJunBase_database\\test")
    val file = new File(parent, s"query_${kind}_annotation.csv")
    val lines = file.csvLines.drop(1)
    val rows = lines.map { columns =>
      QueryJunctionRow(columns(0), columns(1), columns(2), columns(3), columns(4), columns(5), columns(6), columns(7),
        "BS")
    }
    queryJunctionDao.deleteAll(kind).flatMap { x =>
      queryJunctionDao.insertAll(rows)
    }
  }

  def insertQueryBsJunction = Action.async { implicit request =>
    insertQueryBsJunctionF.map { x =>
      Ok("success!")
    }
  }

  def insertQuery = Action.async { implicit request =>
    insertQueryBsJunctionF.zip(insertQueryFsJunctionF).zip(insertQueryLsJunctionF).map { x =>
      Ok("success!")
    }
  }

  def insertDetailBsJunctionF = {
    val kind = "BS"
    val parent = new File("C:\\rJunBase_database\\test")
    val file = new File(parent, s"detail_${kind}_annotation.txt")
    val lines = file.txtLines.drop(1)
    val rows = lines.map { columns =>
      DetailBsRow(columns(0), columns(1), columns(2), columns(3), columns(4), columns(5), columns(6), columns(7),
        columns(8))
    }
    detailBsDao.deleteAll.flatMap { x =>
      detailBsDao.insertAll(rows)
    }
  }

  def insertDetailBsJunction = Action.async { implicit request =>
    insertDetailBsJunctionF.map { x =>
      Ok("success!")
    }
  }

  def insertDetailJunction = Action.async { implicit request =>
    insertDetailBsJunctionF.zip(insertDetailFsJunctionF).zip(insertDetailLsJunctionF).map { x =>
      Ok("success!")
    }
  }

  def insertDetailFsJunctionF = {
    val kind = "FS"
    val parent = new File("C:\\rJunBase_database\\test")
    val file = new File(parent, s"detail_${kind}_annotation.txt")
    val lines = file.txtLines.drop(1)
    val rows = lines.map { columns =>
      DetailFsRow(columns(0), columns(1), columns(2), columns(3), columns(4), columns(5), columns(6), columns(7),
        columns(8), columns(9), columns(10), columns(11))
    }
    detailFsDao.deleteAll.flatMap { x =>
      detailFsDao.insertAll(rows)
    }
  }

  def insertDetailFsJunction = Action.async { implicit request =>
    insertDetailFsJunctionF.map { x =>
      Ok("success!")
    }
  }

  def insertDetailLsJunctionF = {
    val kind = "LS"
    val parent = new File("C:\\rJunBase_database\\test")
    val file = new File(parent, s"detail_${kind}_annotation.txt")
    val lines = file.txtLines.drop(1)
    val rows = lines.map { columns =>
      DetailLsRow(columns(0), columns(1), columns(2), columns(3), columns(4), columns(5), columns(6), columns(7),
        columns(8), columns(9), columns(10), columns(11), columns(12), columns(13), columns(14), columns(15))
    }
    detailLsDao.deleteAll.flatMap { x =>
      detailLsDao.insertAll(rows)
    }
  }

  def insertDetailLsJunction = Action.async { implicit request =>
    insertDetailLsJunctionF.map { x =>
      Ok("success!")
    }
  }

  def insertQueryFsJunctionF = {
    val kind = "FS"
    val parent = new File("C:\\rJunBase_database\\test")
    val file = new File(parent, s"query_${kind}_annotation.csv")
    val lines = file.csvLines.drop(1)
    val rows = lines.map { columns =>
      QueryFsJunctionRow(columns(0), columns(1), columns(2), columns(3), columns(4), columns(5), columns(6),
        columns(7), columns(8), columns(9))
    }
    queryFsJunctionDao.deleteAll.flatMap { x =>
      queryFsJunctionDao.insertAll(rows)
    }
  }

  def insertQueryFsJunction = Action.async { implicit request =>
    insertQueryFsJunctionF.map { x =>
      Ok("success!")
    }
  }

  def insertQueryLsJunctionF = {
    val kind = "LS"
    val parent = new File("C:\\rJunBase_database\\test")
    val file = new File(parent, s"query_${kind}_annotation.csv")
    val lines = file.csvLines.drop(1)
    val rows = lines.map { columns =>
      QueryLsJunctionRow(columns(0), columns(1), columns(2), columns(3), columns(4), columns(5), columns(6), columns(7),
        columns(8), columns(9), columns(10), columns(11), columns(12), columns(13), columns(14))
    }
    queryLsJunctionDao.deleteAll.flatMap { x =>
      queryLsJunctionDao.insertAll(rows)
    }
  }

  def insertQueryLsJunction = Action.async { implicit request =>
    insertQueryLsJunctionF.map { x =>
      Ok("success!")
    }
  }

  def insertFsJunctionF = {
    val kind = "FS"
    val parent = new File("C:\\rJunBase_database\\test")
    val file = new File(parent, "browse_FS_annotation.csv")
    val lines = file.csvLines.drop(1)
    val rows = lines.map { columns =>
      JunctionRow(columns(0), columns(1), columns(2), columns(3), columns(4), columns(5), columns(6), columns(7),
        columns(8), columns(9), columns(10), columns(11), columns(12), columns(13), columns(14), columns(15), "FS")
    }
    junctionDao.insertOrUpdates(rows)
  }

  def insertFsJunction = Action.async { implicit request =>
    insertFsJunctionF.map { x =>
      Ok("success!")
    }
  }

  def insertFsJunctionLocationF = {
    val kind = "FS"
    val parent = new File("C:\\rJunBase_database\\test")
    val file = new File(parent, "browse_FS_annotation.csv")
    val lines = file.csvLines.drop(1)
    val rows = lines.map { columns =>
      val location = columns(1)
      val r = "^(chr[a-zA-Z0-9]+):(\\d+):[^\\|]{1}\\|(chr[a-zA-Z0-9]+):(\\d+):[^\\|]{1}$".r
      val r(chr1, chr1Pos, chr2, chr2Pos) = location
      JunctionLocationRow(columns(0), chr1, chr1Pos.toInt, chr2, chr2Pos.toInt, kind)
    }
    junctionLocationDao.deleteAll(kind).flatMap { x =>
      junctionLocationDao.insertAll(rows)
    }
  }

  def insertFsJunctionLocation = Action.async { implicit request =>
    insertFsJunctionLocationF.map { x =>
      Ok("success!")
    }
  }

  def insertFs = Action.async { implicit request =>
    insertFsJunctionLocationF.zip(insertFsJunctionF).map { x =>
      Ok("success!")
    }
  }

  def insertLsJunctionF = {
    val startTime = System.currentTimeMillis()
    val parent = new File("C:\\rJunBase_database\\test")
    val file = new File(parent, "browse_LS_annotation.csv")
    val kind = "LS"
    val lines = file.csvLines.drop(1)
    val rows = lines.map { columns =>
      JunctionRow(columns(0), columns(1), columns(2), columns(3), columns(4), columns(5), columns(6), columns(7),
        columns(8), columns(9), columns(10), columns(11), columns(12), columns(13), columns(14), columns(15), kind)
    }
    var i = 0
    val num = 200000
    junctionDao.deleteAll(kind).map { x =>
      rows.grouped(num).foreach { datas =>
        val f = junctionDao.insertAll(datas)
        i += 1
        Utils.execFuture(f)
        Utils.logTime(s"${i * num}", startTime)
      }
    }
  }

  def insertLsJunction = Action.async { implicit request =>
    insertLsJunctionF.map { x =>
      Ok("success!")
    }
  }

  def insertLsJunctionLocationF = {
    val kind = "LS"
    val parent = new File("C:\\rJunBase_database\\test")
    val file = new File(parent, "browse_LS_annotation.csv")
    val lines = file.csvLines.drop(1)
    val rows = lines.map { columns =>
      val location = columns(1)
      val r = "^(chr[a-zA-Z0-9]+):(\\d+)\\|(\\d+):[^\\|]{1}$".r
      val r(chr1, chr1Pos, chr2Pos) = location
      JunctionLocationRow(columns(0), chr1, chr1Pos.toInt, chr1, chr2Pos.toInt, kind)
    }
    junctionLocationDao.deleteAll(kind).flatMap { x =>
      junctionLocationDao.insertAll(rows)
    }
  }

  def insertLsJunctionLocation = Action.async { implicit request =>
    insertLsJunctionLocationF.map { x =>
      Ok("success!")
    }
  }

  def insertLs = Action.async { implicit request =>
    insertLsJunctionLocationF.zip(insertLsJunctionF).map { x =>
      Ok("success!")
    }
  }

  def insertJunctionAndLocation = Action.async { implicit request =>
    val lsF = insertLsJunctionLocationF.zip(insertLsJunctionF)
    val bsF = insertBsJunctionF.zip(insertBsJunctionLocationF)
    val fsF = insertFsJunctionLocationF.zip(insertFsJunctionF)
    lsF.zip(bsF).zip(fsF).map { x =>
      Ok("success!")
    }
  }

  def insertFusionSymbols = Action.async { implicit request =>
    val parent = new File("C:\\rJunBase_database\\test")
    val file = new File(parent, "gene_fusion.bed")
    val lines = file.txtLines.drop(1)
    val geneSymbols = lines.flatMap { columns =>
      List(columns(6), columns(7))
    }.distinct.filter(_ != "NA")
    println(geneSymbols.size)
    val row = FusionSymbolsRow(1, Json.toJson(geneSymbols).toString())
    fusionSymbolsDao.deleteAll.flatMap { x =>
      fusionSymbolsDao.insert(row)
    }.map { x =>
      Ok("success!")
    }
  }

  def insertModalSymbols = Action.async { implicit request =>
    val dir = Tool.genePatternDataDir
    val geneSymbols = dir.listDirs.map(_.getName)
    val row = ModalSymbolsRow(1, Json.toJson(geneSymbols).toString())
    modalSymbolsDao.deleteAll.flatMap { x =>
      modalSymbolsDao.insert(row)
    }.map { x =>
      Ok("success!")
    }
  }

  def insertGtexIndex = Action.async { implicit request =>
    val startTime = System.currentTimeMillis()
    val dir = Tool.gtexDataDir
    val indexFile = new File(dir, "GTEx.index")
    val rows = indexFile.txtLines.drop(1).map { columns =>
      GtexIndexRow(columns(0), columns(1).toLong)
    }.distinctBy(_.location)
    gtexIndexDao.deleteAll.flatMap { x =>
      gtexIndexDao.insertAll(rows)
    }.map { x =>
      Utils.logTime(startTime)
      Ok("success!")
    }
  }

  def insertGtexSupplementIndex = Action.async { implicit request =>
    val startTime = System.currentTimeMillis()
    val dir = Tool.gtexDataDir
    val indexFile = new File(dir, "GTEx_supplement.index")
    val rows = indexFile.txtLines.drop(1).map { columns =>
      GtexSupplementIndexRow(columns(0), columns(1).toLong)
    }.distinctBy(_.location)
    gtexSupplementIndexDao.deleteAll.flatMap { x =>
      gtexSupplementIndexDao.insertAll(rows)
    }.map { x =>
      Utils.logTime(startTime)
      Ok("success!")
    }
  }

  def insertPancancerIndex = Action { implicit request =>
    val startTime = System.currentTimeMillis()
    val dir = Tool.pancancerDataDir
    val indexDir = new File(dir, "index")
    VarTool.types.foreach { kind =>
      val indexFile = new File(indexDir, s"${kind}.index")
      val rows = indexFile.txtLines.map { columns =>
        PancancerIndexRow(0, columns(0), kind, columns(1).toLong)
      }
      val f = pancancerIndexDao.insertAll(rows).map { x =>
        Utils.logTime(kind, startTime)
      }
      Utils.execFuture(f)
    }
    Ok("success!")
  }

  def deleteUnknowGeneType = Action.async { implicit request =>
    junctionDao.deleteUnknownGeneType.map { x =>
      Ok("success!")
    }
  }


}
